package org.infodavid.common.model.impl;

import java.util.HashMap;
import java.util.Map;

import org.infodavid.common.model.IPermissions;
import org.infodavid.common.model.impl.AbstractBasicDataObjectImpl;

/**
 * The Class PermissionsImpl.
 */
public class PermissionsImpl extends AbstractBasicDataObjectImpl implements IPermissions {

	/** serialVersionUID. */
	private static final long serialVersionUID = -218296778324507550L;

	/** The permissions. */
	private Map<String,Boolean> permissions;

	/**
	 * The Constructor.
	 * @throws Exception the exception
	 */
	protected PermissionsImpl() throws Exception {
		permissions = new HashMap<String,Boolean>();
	}

	/**
	 * The Constructor.
	 * @param values the values
	 * @throws Exception the exception
	 */
	protected PermissionsImpl(final Map<String,Boolean> values) throws Exception {
		permissions = values;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.model.IPermissions#getValue(java.lang.String)
	 */
	public Boolean getValue(final String feature) {
		final Boolean value;

		synchronized (this) {
			if (permissions == null || permissions.isEmpty()) {
				value = null;
			}
			else {
				value = permissions.get(feature);
			}
		}

		return value;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.model.IPermissions#getValues()
	 */
	public synchronized Map<String,Boolean> getValues() {
		synchronized (this) {
			return permissions;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.model.IPermissions#isAllowed(java.lang.String)
	 */
	public boolean isAllowed(final String feature) {
		final Boolean value = getValue(feature);

		return value == null || !value.booleanValue() ? false : true;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.model.IPermissions#isDefined(java.lang.String)
	 */
	public boolean isDefined(final String feature) {
		final Boolean value = getValue(feature);

		return value != null;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.model.IPermissions#isDenied(java.lang.String)
	 */
	public boolean isDenied(final String feature) {
		final Boolean value = getValue(feature);

		return value == null || !value.booleanValue() ? true : false;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.model.IPermissions#setUndefined(java.lang.String)
	 */
	public void setUndefined(final String feature) {
		synchronized (this) {
			permissions.put(feature, null);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.model.IPermissions#setValue(java.lang.String, java.lang.Boolean)
	 */
	public void setValue(final String feature, final Boolean value) {
		if (feature == null || feature.length() == 0) {
			throw new IllegalArgumentException("Feature key is invalid: " + feature);
		}

		if (value == null) {
			setUndefined(feature);
		}
		else {
			synchronized (this) {
				permissions.put(feature, value);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.model.IPermissions#setValues(java.util.Collection)
	 */
	public synchronized void setValues(final Map<String,Boolean> values) {
		synchronized (this) {
			if (values == null) {
				permissions = new HashMap<String,Boolean>();
			}
			else {
				permissions = values;
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.auth.model.IPermissions#clear()
	 */
	public void clear() {
		setValues(null);
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;

		result = prime * result + (getValues() == null ? 0 : getValues().hashCode());

		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}

		if (obj == null) {
			return false;
		}

		if (!(obj instanceof PermissionsImpl)) {
			return false;
		}

		final PermissionsImpl other = (PermissionsImpl)obj;

		if (getValues() == null) {
			if (other.getValues() != null) {
				return false;
			}
		}
		else if (!getValues().equals(other.getValues())) {
			return false;
		}

		return true;
	}
}
